<?php
namespace app\common\model;
use think\Db;
use think\Loader;


class User
{
    private $userMod;
    private $users;//存储已缓存的用户
    private $input;
    public function __construct()
    {
        $this->userMod=config('user_model');
        $this->input=Loader::model('\\app\\common\\model\\Input');
    }

    /**
     * 使用用户名查找用户信息
     * @param $myUserName
     * @param int $channelId
     * @return array|bool|false|\PDOStatement|string|\think\Model
     */
    public function findUserByName($myUserName,$channelId=1000){
        if(empty($myUserName)){
            return err('用户名不能为空');
        }
        $user=$this->_get_cache_by_name($myUserName,$channelId,'');
        if(empty($user)){
            $user=$this->_get_db_by_name($myUserName,$channelId,[]);
            if(!empty($user)){
                $this->_cache_user($user);
                return $user;
            }else{
                return err('用户名不存在');
            }
        }else{
            return $user;
        }

    }

    /**
     * 使用用户id查找用户信息
     * @param $myUserId
     * @param int $channelId
     * @return array|bool|false|\PDOStatement|string|\think\Model
     */
    public function findUserById($myUserId,$channelId=1000){
        if(empty($myUserId)){
            return err('用户ID不能为空');
        }
        if(isset($this->users[$channelId][$myUserId])){
            return $this->users[$channelId][$myUserId];
        }
        $user=$this->_get_cache_by_id($myUserId,$channelId,'');
        if(empty($user)){
            $user=$this->_get_db_by_id($myUserId,$channelId,[]);
            if(empty($user)){
                $rs=Db::name('user')->where(['sdkdrive_id'=>$myUserId,'channel_id'=>$channelId])->find();
                if(!empty($rs)){
                    $user=$rs;
                    $user['user_game_map']=json_decode($rs['user_game_map'],true);
                }
            }
            if($user){
                $this->_cache_user($user);
                return $user;
            }else{
                return err('用户不存在');
            }
        }else{
            return $user;
        }

    }


    /**
     * 创建角色
     * @param $data
     * @return array
     */
    public function createRole($data)
    {

        if(empty($data['my_user_id'])){
            return [
                'result'=>0,
                'msg'=>'用户id不能为空'
            ];
        }
        $myUserId=$data['my_user_id'];
        if(empty($data['game_id'])){
            return [
                'result'=>0,
                'msg'=>'游戏id不能为空'
            ];
        }
        $gameId=$data['game_id'];
        if(empty($data['channel_id'])){
            return [
                'result'=>0,
                'msg'=>'渠道id不能为空'
            ];
        }
        $channelId=$data['channel_id'];
        if(empty($data['server_id'])){
            return [
                'result'=>0,
                'msg'=>'区服id不能为空'
            ];
        }
        $serverId=$data['server_id'];
        if(empty($data['role_id'])){
            return [
                'result'=>0,
                'msg'=>'角色id不能为空'
            ];
        }
        if($data['channel_id']==1000&&$data['cps_id']==0){
            return [
                'result'=>1,
                'msg'=>'1000-0创角不用处理'
            ];
        }
        $roleId=$data['role_id'];
        $cpsId=get_array_value($data,'cps_id',0);
        $serverName=get_array_value($data,'server_name','');
        $roleName=get_array_value($data,'role_name','');
        $level=get_array_value($data,'level',0);
        $vip=get_array_value($data,'vip',0);
        $partyName=get_array_value($data,'party_name','');
        $deviceType=get_array_value($data,'device_type','');
        $ver=get_array_value($data,'ver','');

        $time=time();

        $userGameMap=$this->getUserGameMap($myUserId,$channelId);
        $change=false;
        if(!isset($userGameMap[$gameId]['channel'])){
            $userGameMap[$gameId]['channel']['channel_id']=$channelId;
            $userGameMap[$gameId]['channel']['cps_id']=$cpsId;
            $userGameMap[$gameId]['channel']['bond_time']=time();
            $change=true;
        }
        if(!isset($userGameMap[$gameId]['server'][$serverId])){
            $userGameMap[$gameId]['server'][$serverId]['server_id']=$serverId;
            $userGameMap[$gameId]['server'][$serverId]['server_name']=$serverName;
            $change=true;

        }
        if(!isset($userGameMap[$gameId]['server'][$serverId]['role'][$roleId])){
            $userGameMap[$gameId]['server'][$serverId]['role'][$roleId]['role_id']=$roleId;
            $userGameMap[$gameId]['server'][$serverId]['role'][$roleId]['role_name']=$roleName;
            $userGameMap[$gameId]['server'][$serverId]['role'][$roleId]['total_charge']=0;
            $userGameMap[$gameId]['server'][$serverId]['role'][$roleId]['create_time']=$time;
            $change=true;
            $ret['msg']='新建角色绑定成功';
        }
        if($change){
            if(!$this->setUserGameMap($myUserId,$channelId,$userGameMap)){
                return [
                    'result'=>0,
                    'msg'=>'更新user_game_map失败'
                ];
            }
        }
        $data=[
            'my_user_id'=>$myUserId,
            'channel_id'=>$channelId,
            'cps_id'=>$cpsId,
            'game_id'=>$gameId,
            'ip'=>request()->ip(),
            'server_id'=>$serverId,
            'server_name'=>$serverName,
            'role_id'=>$roleId,
            'role_name'=>$roleName,
            'level'=>$level,
            'vip'=>$vip,
            'party_name'=>$partyName,
            'level_change_time'=>$time,
            'create_time'=>$time,
            'device_type'=>$deviceType,
            'ver'=>$ver
        ];
        async($this->userMod,'gameUserRole',$data);
        return [
            'result'=>1,
            'msg'=>'ok'
        ];

    }

    /**
     * 创建用户
     * @param $regType
     * @param $uid
     * @param $name
     * @param $password
     * @param $channelId
     * @param $cpsId
     * @param $gameId
     * @return array|bool|false|\PDOStatement|string|\think\Model
     */
    public function makeUser($regType,$uid,$name,$password,$channelId,$cpsId,$gameId)
    {

        $user=array();
        $txt_password='';//一键注册的明文密码
        if($regType=='name'){
            //用户名注册
            if(empty($name)||empty($password)){
                return err('用户名和密码不能为空');
            }
            $user['my_user_id']=$this->makeUserId();
            $user['my_user_name']=$name;
            $user['password']=$password;
            $user['ch_user_id']=$user['my_user_id'];
            $user['ch_user_name']=$name;
            $user['channel_id']=$channelId;
            $user['cps_id']=$cpsId;
            $user['phone_number']='';

            $mili = 4; //米粒
            $phoneTimes = 0; //修改手机号次数
            $accountTimes = 1; //修改用户名次数
            $passwordTimes = 1; //修改密码次数

            if(!match($user['my_user_name'],'USERNAME')){
                return err('用户名规则错误,只能由4到20位的字母,数字或下划线组成');
            }

            $rs=$this->findUserByName($user['my_user_name'],$channelId);
            if(check($rs)){
                return err('用户名已存在');
            }
        }else if($regType=='phone'){
            //手机号注册
            if(empty($name)||empty($password)){
                return err('手机号和密码不能为空');
            }
            $user['my_user_id']=$this->makeUserId();
            $user['my_user_name']=$name;
            $user['password']=$password;
            $user['ch_user_id']=$user['my_user_id'];
            $user['ch_user_name']=$name;
            $user['channel_id']=$channelId;
            $user['cps_id']=$cpsId;
            $user['phone_number']=$name;

            $mili = 6;
            $phoneTimes = 1;
            $accountTimes = 1;
            $passwordTimes = 1;

            if(!match($user['my_user_name'],'PHONE')){
                return err('手机号格式不正确');
            }

            $rs=$this->findUserByName($user['my_user_name'],$channelId);
            if(check($rs)){
                return err('用户名已存在');
            }
        }else if($regType=='auto'){

            //自动注册
            if($password==''){
                $txt_password=make_random_password();
            }else{
                $txt_password=$password;
            }
            $user['my_user_id']=$this->makeUserId();
            $user['my_user_name']=$this->makeUserName();
            $user['password']=sha1($txt_password);
            $user['ch_user_id']=$user['my_user_id'];
            $user['ch_user_name']=$name;
            $user['channel_id']=$channelId;
            $user['cps_id']=$cpsId;
            $user['phone_number']='';


            $mili = 2;
            $phoneTimes = 0;
            $accountTimes = 0;
            $passwordTimes = 0;

            $rs=$this->findUserByName($user['my_user_name'],$channelId);
            if(check($rs)){
                Out::exception('自动注册失败,请再试一次.error:U0028');
            }
        }else if($regType=='chuser'){
            $user['my_user_id']=$this->makeUserId();
            $user['my_user_name']=$channelId.'_'.$uid;
            $user['password']='';
            $user['ch_user_id']=$uid;
            $user['ch_user_name']=$name;
            $user['channel_id']=$channelId;
            $user['cps_id']=$cpsId;
            $user['phone_number']='';

            $mili = 0;
            $phoneTimes = 0;
            $accountTimes = 0;
            $passwordTimes = 0;
        }else{
            Out::exception('注册类型错误.error:U0027');
        }

        $rs=$this->findUserById($user['my_user_id'],$channelId);
        if(check($rs)){
            Out::exception('用户ID已存在.error:U0026');
        }
        $cacheData['my_user_id']=$user['my_user_id'];
        $cacheData['my_user_name']=$user['my_user_name'];
        $cacheData['password']=$user['password'];
        $cacheData['total_charge']=0;
        $cacheData['balance']=0;
        $cacheData['sub_account']='';
        $cacheData['channel_id']=$user['channel_id'];
        $cacheData['reg_cps_id']=$user['cps_id'];
        $cacheData['reg_game_id']=empty($gameId)?0:$gameId;
        $cacheData['reg_time']=time();
        $cacheData['phone_number']=$user['phone_number'];
        $cacheData['pay_password']='';
        $cacheData['mili']=isset($mili) ? $mili : 0;
        $cacheData['nick_name']=$user['my_user_name'];
        $cacheData['true_name']='';
        $cacheData['id_card']='';
        $cacheData['cp_user_id']='';
        $cacheData['ch_user_id']=$user['ch_user_id'];//渠道注册时填渠道用户id,否则填米娱id
        $cacheData['ch_user_name']=$user['ch_user_name'];
        $cacheData['email']='';
        $cacheData['reg_type']=$regType;
        $cacheData['device_type']='';
        $cacheData['security']='';
        $cacheData['last_login_time']=time();
        $cacheData['status']=1;
        $cacheData['head_path']='default.png';
        $cacheData['account_times']=isset($accountTimes) ? $accountTimes : 0;
        $cacheData['phone_times']=isset($phoneTimes) ? $phoneTimes : 0;
        $cacheData['password_times']=isset($passwordTimes) ? $passwordTimes : 0;
        $cacheData['user_game_map']=[];
        $cacheData['session_id']=make_session_id($user['my_user_id'],$channelId);
        $cacheData['token']=md5(time(). rand(0, 1000));


        $rs=async($this->userMod,'addUser',$cacheData,true);
        if(!check($rs))return $rs;
        $this->_cache_user($cacheData);

        $cacheData['myUserName']=$cacheData['my_user_name'];
        $cacheData['myUserId']=$cacheData['my_user_id'];
        $cacheData['sessionId']=$cacheData['session_id'];

        if($regType=='auto'){
            $cacheData['password']=$txt_password;
        }

        return $cacheData;
    }

    /**
     * 生成用户id
     * @return bool|int|mixed
     */
    public function makeUserId(){
        $id=0;
        Db::startTrans();
        try{
            $db=Db::name('common');
            $db->where(['key'=>'user_id_index'])->setInc('value');
            $rs=$db->where(['key'=>'user_id_index'])->find();
            $id=$rs['value'];
            // 提交事务
            Db::commit();
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
        }
        if($id==0){
            Out::exception('用户id生成失败');
            return false;
        }else{
            return $id;
        }

    }

    /**
     * 生成用户名
     * @return bool|string
     */
    public function makeUserName(){

        $config=config('user_prefix');
        $prefix=$config==''?'my2':$config;
        $length=config('user_name_length');
        $id=0;
        Db::startTrans();
        try{
            $db=Db::name('common');
            $db->where(['key'=>'user_name_index'])->setInc('value');
            $rs=$db->where(['key'=>'user_name_index'])->find();
            $id=$rs['value'];
            // 提交事务
            Db::commit();
        } catch (\Exception $e) {
            // 回滚事务
            Db::rollback();
        }
        if($id==0){
            Out::exception('用户name生成失败');
            return false;
        }else{
            $name=str_pad($id,$length,'0',STR_PAD_LEFT);
            return $prefix.$name;
        }


    }

    /**
     * 米娱账号登录
     * @param $data
     * @return array|bool|false|\PDOStatement|string|\think\Model
     */
    public function miyuhaiwaiLogin($data){
        $channelId=1000;
        $myUserName=get_array_value($data,'my_user_name','');
        $password=get_array_value($data,'password','');
        $gameId=get_array_value($data,'game_id','');
        $cpsId=get_array_value($data,'cps_id','');
        $deviceId=get_array_value($data,'device_id','');
        $deviceType=get_array_value($data,'device_type','');
        $ver=get_array_value($data,'ver','');
        $ip=request()->ip();

        if($cpsId==1320&&$gameId==1238){

            return err('该渠道已被封停');
        }

        if(!match($myUserName,'USERNAME')){
            Out::exception('error:U0016');
        }
        if(!match($password,'PASSWORD')){
            Out::exception('error:U0017');
        }
        if(empty($cpsId))Out::exception('error:U0019');
        //if(empty($gameId))Out::exception('error:U0020');

        $user=$this->findUserByName($myUserName,$channelId);
        if(check($user)){
            if(strcmp(strtolower($user['password']),strtolower($password))==0){
                $sessionId=make_session_id($user['my_user_id'],$channelId);
                $this->_update_cache_by_name($myUserName,$channelId,'session_id',$sessionId);
                if($user['status']!=1){
                    return err('该账号禁止登录');
                }

                if($user['reg_type']=='auto'&&$user['account_times']<=0){
                    $chgName=1;
                }else{
                    $chgName=0;
                }

                $updateData=[
                    'my_user_name'=>$myUserName,
                    'channel_id'=>$channelId,
                    'session_id'=>$sessionId
                ];
                async($this->userMod,'updateUserByName',$updateData);
                $userLog=[
                    'my_user_id'=>$user['my_user_id'],
                    'time'=>time(),
                    'login_ip'=>$ip,
                    'channel_id'=>$channelId,
                    'game_id'=>$gameId,
                    'cps_id'=>$cpsId,
                    'device_id'=>$deviceId,
                    'ver'=>$ver,
                    'device_type'=>$deviceType
                ];
                async(config('user_model'),'userLog',$userLog);
                $online=[
                    'my_user_id'=>$user['my_user_id'],
                    'time'=>time(),
                    'login_ip'=>$ip,
                    'channel_id'=>$channelId,
                    'game_id'=>$gameId,
                    'cps_id'=>$cpsId,
                    'device_id'=>$deviceId,
                ];
                async(config('user_model'),'online',$online);
                $gameUser=[
                    'my_user_id'=>$user['my_user_id'],
                    'channel_id'=>$channelId,
                    'cps_id'=>$cpsId,
                    'game_id'=>$gameId,
                    'bond_time'=>time(),
                    'device_type'=>$deviceType,
                ];
                async($this->userMod,'gameUser',$gameUser);
                $this->enterGame($gameUser);
                /*$gameUserLog=[
                    'my_user_id'=>$user['my_user_id'],
                    'channel_id'=>$channelId,
                    'cps_id'=>$cpsId,
                    'game_id'=>$gameId,
                    'server_id'=>'',
                    'server_name'=>'',
                    'role_id'=>'',
                    'role_name'=>'',
                    'level'=>0,
                    'vip'=>0,
                    'party_name'=>'',
                    'start_time'=>$user['reg_time'],
                    'in_time'=>time(),
                    'device_type'=>$deviceType,
                    'ip'=>$ip,
                    'ver'=>$ver
                ];
                async($this->userMod,'gameUserLog',$gameUserLog);*/
                if($user['my_user_id']<config('sdk2_start_id_index')){//老用户登录返回sdk_id
                    $user['my_user_id']=$user['sdk_id'];
                }
                return suc(
                    [
                        'my_user_id'=>$user['my_user_id'],
                        'my_user_name'=>$user['my_user_name'],
                        'session_id'=>$sessionId,
                        'chgName'=>$chgName,
                        'phone_number'=>$user['phone_number'],
                        'account_times'=>$user['account_times']
                    ]
                );

            }else{
                return err('密码错误');
            }
        }else{
            return $user;
        }
    }

    /**
     * 注销
     * @param $data
     * @return bool
     */
    public function logout($data){
        $myUserId=get_array_value($data,'my_user_id','');
        $channelId=get_array_value($data,'channel_id','');
        if(empty($myUserId)){

            Out::exception('error:U0021');
        }

        $this->_update_cache_by_id($myUserId,$channelId,'session_id','');
        $updateData=[
            'my_user_id'=>$myUserId,
            'channel_id'=>$channelId,
            'session_id'=>''
        ];
        async($this->userMod,'updateUserById',$updateData);

        $this->offline(['my_user_id'=>$myUserId,'channel_id'=>$channelId]);

        return true;
    }

    /**
     * 渠道用户登录
     * @param $data
     * @return array|bool|false|\PDOStatement|string|\think\Model
     */
    public function channelGameLogin($data){
        $chUserId=get_array_value($data,'ch_user_id','');
        $chUserName=get_array_value($data,'ch_user_name','');
        $channelId=get_array_value($data,'channel_id','');
        $gameId=get_array_value($data,'game_id','');
        $cpsId=get_array_value($data,'cps_id','');
        $deviceId=get_array_value($data,'device_id','');
        $deviceType=get_array_value($data,'device_type','');
        $ver=get_array_value($data,'ver','');
        $ip=request()->ip();


        //查找渠道用户是否存在,如果存在则登录获取session_id,否则就创建新用户并登录
        $channelUser=$this->findUserByChUid($chUserId,$channelId);
        if(check($channelUser)){
            $data=[
                'session_id'=>make_session_id($channelUser['my_user_id'],$channelId),
                'last_login_time'=>time()
            ];

            $this->_update_cache_by_id($channelUser['my_user_id'],$channelId,$data);
            $data['my_user_id']=$channelUser['my_user_id'];
            $data['channel_id']=$channelId;
            async($this->userMod,'updateUserById',$data);
            if($channelUser['my_user_id']<=config('sdk2_start_id_index')){//如果id小于新系统的起始id,说明是老用户,需要转换
                //特殊处理的游戏
                if($gameId=='1047'||$gameId=='1186'){
                    if($channelId==1000){
                        $ret['my_user_id']=$channelUser['sdkdrive_uid'];
                    }else{
                        $ret['my_user_id']=$channelUser['sdkdrive_g_uid'];
                    }
                }else{
                    $ret['my_user_id']=$channelUser['sdkdrive_id'];
                }
            }else{
                $ret['my_user_id']=$channelUser['my_user_id'];//新id
            }
            $ret['session_id']=$data['session_id'];
            if($channelId!=1000){
                $userLog=[
                    'my_user_id'=>$channelUser['my_user_id'],
                    'time'=>time(),
                    'login_ip'=>$ip,
                    'channel_id'=>$channelId,
                    'game_id'=>$gameId,
                    'cps_id'=>$cpsId,
                    'device_id'=>$deviceId,
                    'ver'=>$ver,
                    'device_type'=>$deviceType
                ];
                async(config('user_model'),'userLog',$userLog);
                //$this->userLog($userLog);
                $online=[
                    'my_user_id'=>$channelUser['my_user_id'],
                    'time'=>time(),
                    'login_ip'=>$ip,
                    'channel_id'=>$channelId,
                    'game_id'=>$gameId,
                    'cps_id'=>$cpsId,
                    'device_id'=>$deviceId,
                ];
                async(config('user_model'),'online',$online);
                $gameUser=[
                    'my_user_id'=>$channelUser['my_user_id'],
                    'channel_id'=>$channelId,
                    'cps_id'=>$cpsId,
                    'game_id'=>$gameId,
                    'bond_time'=>time(),
                    'device_type'=>$deviceType,
                ];
                async($this->userMod,'gameUser',$gameUser);

                $gameUserLog=[
                    'my_user_id'=>$channelUser['my_user_id'],
                    'channel_id'=>$channelId,
                    'cps_id'=>$cpsId,
                    'game_id'=>$gameId,
                    'server_id'=>'',
                    'server_name'=>'',
                    'role_id'=>'',
                    'role_name'=>'',
                    'level'=>0,
                    'vip'=>0,
                    'party_name'=>'',
                    'start_time'=>$channelUser['reg_time'],
                    'in_time'=>time(),
                    'device_type'=>$deviceType,
                    'ip'=>$ip,
                    'ver'=>$ver,
                    'client_id'=>Input::getClientId()
                ];
                async($this->userMod,'gameUserLog',$gameUserLog);
            }

        }else{
            $rs=$this->makeUser('chuser',$chUserId,$chUserName,'',$channelId,0,$gameId);
            if(!check($rs)){
                return $rs;
            }
            $ret['my_user_id']=$rs['my_user_id'];
            $ret['session_id']=$rs['session_id'];

            $userLog=[
                'my_user_id'=>$ret['my_user_id'],
                'time'=>time(),
                'login_ip'=>request()->ip(),
                'channel_id'=>$channelId,
                'game_id'=>$gameId,
                'cps_id'=>$cpsId,
                'device_id'=>$deviceId,
                'ver'=>$ver,
                'device_type'=>$deviceType
            ];
            async($this->userMod,'userLog',$userLog);

            $online=[
                'my_user_id'=>$ret['my_user_id'],
                'time'=>time(),
                'login_ip'=>request()->ip(),
                'channel_id'=>$channelId,
                'game_id'=>$gameId,
                'cps_id'=>$cpsId,
                'device_id'=>$deviceId,
            ];
            async($this->userMod,'online',$online);
            $gameUser=[
                'my_user_id'=>$ret['my_user_id'],
                'channel_id'=>$channelId,
                'cps_id'=>$cpsId,
                'game_id'=>$gameId,
                'bond_time'=>time(),
                'device_type'=>$deviceType,
            ];
            async($this->userMod,'gameUser',$gameUser);
            $gameUserLog=[
                'my_user_id'=>$ret['my_user_id'],
                'channel_id'=>$channelId,
                'cps_id'=>$cpsId,
                'game_id'=>$gameId,
                'server_id'=>'',
                'server_name'=>'',
                'role_id'=>'',
                'role_name'=>'',
                'level'=>0,
                'vip'=>0,
                'party_name'=>'',
                'start_time'=>time(),
                'in_time'=>time(),
                'device_type'=>$deviceType,
                'ip'=>$ip,
                'ver'=>$ver,
                'client_id'=>Input::getClientId()
            ];
            async($this->userMod,'gameUserLog',$gameUserLog);

        }


        return $ret;
    }


    /**
     * @param $chUserId
     * @param $channelId
     * @return array|bool|false|\PDOStatement|string|\think\Model
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function findUserByChUid($chUserId,$channelId){
        if(empty($chUserId)){
            Out::exception('error:U0022');
        }
        $redis=new Redis();
        $key='user:'.$channelId.':ch:'.$chUserId;
        $channelUser=$redis->hGetAll($key);
        if($channelUser){
            $user=$this->findUserById($channelUser['my_user_id'],$channelId);
            $redis->expire($key,config('user_ttl'));
            return $user;
        }else{
            $channelUser=Db::name('user')
                ->where(['ch_user_id'=>$chUserId,'channel_id'=>$channelId])
                ->find();
            if($channelUser){
                $channelUser['user_game_map']=json_decode($channelUser['user_game_map'],true);
                $this->_cache_user($channelUser);
                $data=[
                    'my_user_id'=>$channelUser['my_user_id'],
                ];
                $redis->hMset($key,$data);
                $redis->expire($key,config('user_ttl'));
                return $channelUser;
            }else{
                return err('用户不存在');
            }
        }

    }
    /**
     * 保存手机号码
     * @param $myUserName
     * @param $phoneNumber
     * @param int $channelId
     * @return bool
     */
    public function savePhoneNumber($myUserName,$phoneNumber,$channelId=1000){
        $this->_update_cache_by_name($myUserName,$channelId,'phone_number',$phoneNumber);

        $updateData=[
            'my_user_name'=>$myUserName,
            'channel_id'=>$channelId,
            'phone_number'=>$phoneNumber
        ];
        async($this->userMod,'updateUserByName',$updateData);

        return true;
    }

    /**
     * 用户信息插入数据库
     * @param $user
     * @return bool
     */
    public function addUser($user){
        try{
            $rs=Db::name('user')->insert($user);
            if($rs){
                return suc('用户保存成功');
            }else{
                return suc('用户保存失败.code:u1000');
            }

        }catch(\Exception $e){
            return err($e->getMessage());
        }
    }

    /**
     * user信息插入数据库
     * @param $user
     * @return bool|int|string
     */
    public function updateUserById($user){
        $myUserId=isset($user['my_user_id'])?$user['my_user_id']:'';
        $channelId=isset($user['channel_id'])?$user['channel_id']:1000;
        return $this->_update_db_by_id($myUserId,$channelId,$user);
    }

    public function updateUserByName($user){
        $myUserName=isset($user['my_user_name'])?$user['my_user_name']:'';
        $channelId=isset($user['channel_id'])?$user['channel_id']:1000;
        return $this->_update_db_by_name($myUserName,$channelId,$user);
    }




    /**
     * 修改密码
     * @param $myUserName
     * @param $oldPasswd
     * @param $newPasswd
     * @param int $channelId
     * @return bool
     */
    public function chgPasswd($myUserName,$oldPasswd,$newPasswd,$channelId=1000){

        if(!match($newPasswd,'PASSWORD')){
            return err('密码格式错误');
        }

        $user=$this->findUserByName($myUserName,$channelId);
        if($user){
            if($user['password']==$oldPasswd){
                $this->_update_cache_by_name($myUserName,$channelId,'password',$newPasswd);
                $updateData=[
                    'my_user_name'=>$myUserName,
                    'channel_id'=>$channelId,
                    'password'=>$newPasswd
                ];
                async($this->userMod,'updateUserByName',$updateData);

                return suc();
            }else{
                return err('原密码验证错误');
            }
        }else{
            return err('用户不存在');
        }
    }

    /**
     * 更新密码
     * @param $myUserName
     * @param $newPasswd
     * @param int $channelId
     * @return bool
     */
    public function updatePasswd($myUserName,$newPasswd,$channelId=1000){

        $user=$this->findUserByName($myUserName,$channelId);
        if($user){
            $this->_update_cache_by_name($myUserName,$channelId,'password',$newPasswd);

            $updateData=[
                'my_user_name'=>$myUserName,
                'channel_id'=>$channelId,
                'password'=>$newPasswd
            ];
            async($this->userMod,'updateUserByName',$updateData);

            return suc();
        }else{
            return err('用户不存在');
        }
    }

    /**
     * 检查用户的密码是否正确
     * @param $myUserName
     * @param $passwd
     * @param int $channelId
     * @return bool
     */
    public function checkPasswd($myUserName,$passwd,$channelId=1000){
        if(!match($myUserName,'USERNAME')){
            Out::exception('用户名格式错误');
        }
        if(!match($passwd,'PASSWORD')){
            Out::exception('原密码格式错误');
        }

        $user=$this->findUserByName($myUserName,$channelId);
        if($user){
            if($user['password']==$passwd){
                return true;
            }else{
                return false;
            }
        }else{
            return false;
        }
    }

    /**
     * 获取角色信息
     * @param $myUserId
     * @param $channelId
     * @param $gameId
     * @param $serverId
     * @param $roleId
     * @return bool
     */
    public function getRole($myUserId,$channelId,$gameId,$serverId,$roleId){
        $user=$this->findUserById($myUserId,$channelId);
        if($user){
            $userGameMap=isset($user['user_game_map'])?$user['user_game_map']:[];
            if(isset($userGameMap[$gameId]['server'][$serverId]['role'][$roleId])){
                return $userGameMap[$gameId]['server'][$serverId]['role'][$roleId];
            }else{
                return false;
            }
        }else{
            return false;
        }

    }


    /**
     * 保存use_game_map,同时更新数据库
     * @param $myUserId
     * @param $channelId
     * @param $value
     * @return bool
     */
    public function setUserGameMap($myUserId,$channelId,$ugm){

        $user=$this->findUserById($myUserId,$channelId);
        if($user){
            $this->_update_cache_by_id($myUserId,$channelId,'user_game_map',json_encode($ugm));
            $updateData=[
                'my_user_id'=>$myUserId,
                'channel_id'=>$channelId,
                'user_game_map'=>json_encode($ugm)
            ];
            async($this->userMod,'updateUserById',$updateData);

            return true;
        }else{
            return false;
        }
    }

    /**
     * 获取user_game_map
     * @param $myUserId
     * @param $channelId
     * @return bool|mixed
     */
    public function getUserGameMap($myUserId,$channelId){

        $user=$this->findUserById($myUserId,$channelId);

        if(!isset($user['ugm_isset'])||$user['ugm_isset']!=1){
            //需要强制更新ugm
            $ugm=[];
            $db=Db::connect();
            $tables=$db->getTables(config('database.database'));
            $prefix=config('database.prefix');
            $game_user=[];
            $game_user_role=[];
            krsort($tables);
            foreach($tables as $v){
                if(match($v,"/^{$prefix}game_user_y_20[0-9][0-9]$/")){
                    $gu=$db->table($v)
                        ->where(['my_user_id'=>$myUserId])
                        ->select();
                    if($gu){
                        $game_user=array_merge($game_user,$gu);
                    }
                }
                if(match($v,"/^{$prefix}game_user_role_y_20[0-9][0-9]$/")){
                    $gur=$db->table($v)
                        ->where(['my_user_id'=>$myUserId])
                        ->select();
                    if($gur){
                        $game_user_role=array_merge($game_user_role,$gur);
                    }
                }
            }
            foreach ($game_user as $v) {
                if(!isset($ugm[$v['game_id']])){
                    $ugm[$v['game_id']]['channel']['channel_id']=$v['channel_id'];
                    $ugm[$v['game_id']]['channel']['cps_id']=$v['cps_id'];
                    $ugm[$v['game_id']]['channel']['bond_time']=$v['bond_time'];
                }
            }
            foreach($game_user_role as $v){
                if(!isset($ugm[$v['game_id']]['channel'])){
                    $ugm[$v['game_id']]['channel']['channel_id']=$v['channel_id'];
                    $ugm[$v['game_id']]['channel']['cps_id']=$v['cps_id'];
                    $ugm[$v['game_id']]['channel']['bond_time']=$v['create_time'];
                }
                if(!isset($ugm[$v['game_id']]['server'][$v['server_id']])){
                    $ugm[$v['game_id']]['server'][$v['server_id']]['server_id']=$v['server_id'];
                    $ugm[$v['game_id']]['server'][$v['server_id']]['server_name']=$v['server_name'];
                }

                if(!isset($ugm[$v['game_id']]['server'][$v['server_id']]['role'])){
                    $ugm[$v['game_id']]['server'][$v['server_id']]['role'][$v['role_id']]['role_id']=$v['role_id'];
                    $ugm[$v['game_id']]['server'][$v['server_id']]['role'][$v['role_id']]['role_name']=$v['role_name'];
                    $ugm[$v['game_id']]['server'][$v['server_id']]['role'][$v['role_id']]['total_charge']=0;
                    $ugm[$v['game_id']]['server'][$v['server_id']]['role'][$v['role_id']]['create_time']=$v['create_time'];
                }
            }

            $this->_update_cache_by_id($myUserId,$channelId,['user_game_map'=>json_encode($ugm),'ugm_isset'=>1]);
            $updateData=[
                'my_user_id'=>$myUserId,
                'channel_id'=>$channelId,
                'user_game_map'=>json_encode($ugm),
                'ugm_isset'=>1
            ];
            async($this->userMod,'updateUserById',$updateData);
            return $ugm;

        }else{
            if(isset($user['user_game_map'])){
                return $user['user_game_map'];
            }else{
                Out::exception('error:U0001');
                return [];
            }
        }

    }



    /**
     * 获取用户名
     * @param $myUserId
     * @param $channelId
     * @return bool|mixed
     */
    public function getUserName($myUserId,$channelId){
        $user=$this->findUserById($myUserId,$channelId);
        if($user){
            return $user['my_user_name'];
        }else{
            return false;
        }
    }

    /**
     * 修改角色名
     * @param $data
     * @return bool
     * @throws \think\Exception
     */
    public function chgRoleName($data){
        if(!isset($data['my_user_id']))return false;
        if(!isset($data['channel_id']))return false;
        if(!isset($data['game_id']))return false;
        if(!isset($data['server_id']))return false;
        if(!isset($data['role_id']))return false;
        if(!isset($data['role_name']))return false;
        $myUserId=$data['my_user_id'];
        $channelId=$data['channel_id'];
        $gameId=$data['game_id'];
        $serverId=$data['server_id'];
        $roleId=$data['role_id'];
        $roleName=$data['role_name'];
        $ugm=$this->getUserGameMap($myUserId,$channelId);

        if(isset($ugm[$gameId]['server'][$serverId]['role'][$roleId]['role_name'])){
            $ugm[$gameId]['server'][$serverId]['role'][$roleId]['role_name']=$roleName;
            $create_time=$ugm[$gameId]['server'][$serverId]['role'][$roleId]['create_time'];
            $year=date('Y',$create_time);
            Db::name('game_user_role_y_'.$year)
                ->where(['my_user_id'=>$myUserId])
                ->where(['channel_id'=>$channelId])
                ->where(['game_id'=>$gameId])
                ->where(['server_id'=>$serverId])
                ->where(['role_id'=>$roleId])
                ->update(['role_name'=>$roleName]);
        }else{
            $db=Db::connect();
            $tables=$db->getTables(config('database.database'));
            $prefix=config('database.prefix');
            krsort($tables);
            foreach($tables as $v){
                if(match($v,"/^{$prefix}game_user_role_y_20[0-9][0-9]$/")){
                    $db->table($v)
                        ->where(['my_user_id'=>$myUserId])
                        ->where(['channel_id'=>$channelId])
                        ->where(['game_id'=>$gameId])
                        ->where(['server_id'=>$serverId])
                        ->where(['role_id'=>$roleId])
                        ->update(['role_name'=>$roleName]);
                    break;
                }

            }
        }
        return true;

    }

    /**
     * 进入游戏
     * @param $data
     * @return array
     */
    public function enterGame($user){
        $data=[
            'my_user_id'=>get_array_value($user,'my_user_id',0),
            'channel_id'=>get_array_value($user,'channel_id',0),
            'cps_id'=>get_array_value($user,'cps_id',0),
            'game_id'=>get_array_value($user,'game_id',0),
            'server_id'=>get_array_value($user,'server_id',0),
            'server_name'=>get_array_value($user,'server_name',0),
            'role_id'=>get_array_value($user,'role_id',0),
            'role_name'=>get_array_value($user,'role_name',0),
            'party_name'=>get_array_value($user,'party_name',0),
            'level'=>get_array_value($user,'level',0),
            'vip'=>get_array_value($user,'vip',0),
            'in_time'=>get_array_value($user,'in_time',time()),
            //'start_time'=>isset($userGameMap[$gameId])?$userGameMap[$gameId]['channel']['bond_time']:$time,
            'device_type'=>get_array_value($user,'device_type',0),
            'ip'=>get_array_value($user,'ip',request()->ip()),
            'ver'=>get_array_value($user,'ver',0)
        ];

        if(empty($data['my_user_id'])||empty($data['channel_id'])){
            return ['result'=>0,'msg'=>'用户id或渠道id不能为空'];
        }

        $user=$this->findUserById($data['my_user_id'],$data['channel_id']);
        if(!$user){
            return ['result'=>0,'msg'=>'用户不存在'];
        }
        if($data['channel_id']==1000&&$data['cps_id']==0){
            return ['result'=>1,'msg'=>'1000-0不用处理'];
        }

        $time=time();
        $userGameMap=$this->getUserGameMap($data['my_user_id'],$data['channel_id']);
        //game_user_log
        if(isset($userGameMap[$data['game_id']])){
            if(!isset($userGameMap[$data['game_id']]['channel']['bond_time'])){
                $userGameMap[$data['game_id']]['channel']['bond_time']=$time;
            }
            $data['start_time']=$userGameMap[$data['game_id']]['channel']['bond_time'];
        }else{
            $data['start_time']=$time;
        }

        async($this->userMod,'gameUserLog',$data);
        //game_user
        if(!isset($userGameMap[$data['game_id']])){
            $userGameMap[$data['game_id']]['channel']['channel_id']=$data['channel_id'];
            $userGameMap[$data['game_id']]['channel']['cps_id']=$data['cps_id'];
            $userGameMap[$data['game_id']]['channel']['bond_time']=$time;
            $this->setUserGameMap($data['my_user_id'],$data['channel_id'],$userGameMap);
            $gameUser=[
                'my_user_id'=>$data['my_user_id'],
                'channel_id'=>$data['channel_id'],
                'cps_id'=>$data['cps_id'],
                'game_id'=>$data['game_id'],
                'bond_time'=>$time,
                'device_type'=>$data['device_type'],
            ];
            async($this->userMod,'gameUser',$gameUser);
            return suc('ok');
        }else{
            return suc('用户已绑定');
        }

    }

    /**
     * 获取角色充值总金额
     * @param $myUserId
     * @param $channelId
     * @param $gameId
     * @param $serverId
     * @param $roleId
     * @return float|int
     */
    public function getRoleCharge($myUserId,$channelId,$gameId,$serverId,$roleId){
        $db=Db::connect();
        $tables=$db->getTables(config('database.database'));
        $prefix=config('database.prefix');

        krsort($tables);
        $sum_price=0;
        foreach($tables as $v){
            if(match($v,"/^{$prefix}pay_order_y_20[0-9][0-9]$/")){
                $total=$db->table($v)
                    ->where(['my_user_id'=>$myUserId])
                    ->where(['channel_id'=>$channelId])
                    ->where(['game_id'=>$gameId])
                    ->where(['server_id'=>$serverId])
                    ->where(['role_id'=>$roleId])
                    ->where("pay_time>0 or debug=1")
                    ->sum('total_price');
                $sum_price+=$total;
            }

        }
        return $sum_price;
    }

    /**
     * 更新角色等级
     * @param $data
     * @return array
     */
    public function chgLevel($data){
        if(!isset($data['my_user_id']))return false;
        if(!isset($data['channel_id']))return false;
        if(!isset($data['game_id']))return false;
        if(!isset($data['server_id']))return false;
        if(!isset($data['role_id']))return false;
        if(!isset($data['level']))return false;
        $myUserId=$data['my_user_id'];
        $channelId=$data['channel_id'];
        $gameId=$data['game_id'];
        $serverId=$data['server_id'];
        $roleId=$data['role_id'];
        $level=$data['level'];
        $ugm=$this->getUserGameMap($myUserId,$channelId);

        if(isset($ugm[$gameId]['server'][$serverId]['role'][$roleId]['create_time'])){
            $create_time=$ugm[$gameId]['server'][$serverId]['role'][$roleId]['create_time'];
            $year=date('Y',$create_time);
            Db::name('game_user_role_y_'.$year)
                ->where(['my_user_id'=>$myUserId])
                ->where(['channel_id'=>$channelId])
                ->where(['game_id'=>$gameId])
                ->where(['server_id'=>$serverId])
                ->where(['role_id'=>$roleId])
                ->update(['level'=>$level]);
        }else{
            $db=Db::connect();
            $tables=$db->getTables(config('database.database'));
            $prefix=config('database.prefix');
            krsort($tables);
            foreach($tables as $v){
                if(match($v,"/^{$prefix}game_user_role_y_20[0-9][0-9]$/")){
                    $db->table($v)
                        ->where(['my_user_id'=>$myUserId])
                        ->where(['channel_id'=>$channelId])
                        ->where(['game_id'=>$gameId])
                        ->where(['server_id'=>$serverId])
                        ->where(['role_id'=>$roleId])
                        ->update(['level'=>$level]);
                    break;
                }

            }
        }
        return true;



    }



    /**
     * 记录user_log日志
     * @param $data
     * @return bool
     */
    public function userLog($userLog){
        $data=[
            'my_user_id'=>get_array_value($userLog,'my_user_id',''),
            'time'=>get_array_value($userLog,'time',time()),
            'login_ip'=>get_array_value($userLog,'login_ip',''),
            'channel_id'=>get_array_value($userLog,'channel_id',''),
            'game_id'=>get_array_value($userLog,'game_id',''),
            'cps_id'=>get_array_value($userLog,'cps_id',''),
            'device_id'=>get_array_value($userLog,'device_id',''),
            'ver'=>get_array_value($userLog,'ver',''),
            'device_type'=>get_array_value($userLog,'device_type',''),
            'client_id'=>$this->input->getClientId()
        ];

        if(empty($data['my_user_id'])||empty($data['channel_id'])||empty($data['game_id'])){
            Log::record('User->userLog:数据不全'.json_encode($userLog));
            return false;
        }

        $time=time();
        $month=date('Ym',$time);
        $db=Db::connect();
        $tables=$db->getTables(config('database.database'));
        $prefix=config('database.prefix');
        krsort($tables);
        $tableExists=false;
        foreach($tables as $v){
            if($v==$prefix.'user_log_m_'.$month){
                $tableExists=true;
                break;
            }
        }
        if(!$tableExists){
            $sql = "CREATE TABLE `{$prefix}user_log_m_{$month}` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `my_user_id` varchar(16) NOT NULL,
  `time` int(10) unsigned DEFAULT '0',
  `login_ip` varchar(15) DEFAULT NULL,
  `channel_id` int(10) unsigned DEFAULT '0',
  `game_id` int(10) unsigned DEFAULT '0',
  `cps_id` int(11) DEFAULT NULL,
  `device_id` varchar(64) DEFAULT '',
  `ver` varchar(10) DEFAULT '',
  `device_type` varchar(20) DEFAULT NULL,
  `client_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户登录日志';";

            try{
                Db::execute($sql);//创建表
            }catch(\Exception $e){
                Log::record('create user_log_m_'.$month.' table error.'.$e->getMessage(),'error','error');
            }
        }

        try{

            Db::name('user_log_m_'.$month)->insert($data);
            return true;
        }catch(\Exception $e){
            Log::record($e->getMessage().'|userLog|'.json_encode($data),'error','error');
            return false;
        }
    }


    public function online($user){
        $data=[
            'my_user_id'=>get_array_value($user,'my_user_id',''),
            'time'=>get_array_value($user,'time',time()),
            'login_ip'=>get_array_value($user,'login_ip',request()->ip()),
            'channel_id'=>get_array_value($user,'channel_id',''),
            'game_id'=>get_array_value($user,'game_id',''),
            'cps_id'=>get_array_value($user,'cps_id',''),
            'device_id'=>get_array_value($user,'device_id',''),
            'client_id'=>$this->input->getClientId(),
        ];
        if(empty($data['my_user_id'])||empty($data['channel_id'])){
            Log::record('online:无法获取myUserId或channelId');
            return false;
        }

        try{

            $rs=Db::name('user_online')
                ->where(['my_user_id'=>$data['my_user_id'],'channel_id'=>$data['channel_id'],'game_id'=>$data['game_id']])
                ->find();
            if(empty($rs)){
                Db::name('user_online')
                    ->insert($data);
            }else{
                Db::name('user_online')
                    ->where(['my_user_id'=>$data['my_user_id'],'channel_id'=>$data['channel_id'],'game_id'=>$data['game_id']])
                    ->update(['time'=>time()]);
            }

            return true;
        }catch(\Exception $e){
            Log::record($e->getMessage().'|online|'.json_encode($data),'error','error');
            return false;
        }

    }
    public function offline($data){
        $myUserId=get_array_value($data,'my_user_id','');
        $channelId=get_array_value($data,'channel_id','');
        if(empty($myUserId)||empty($channelId)){
            return false;
        }

        try{
            Db::name('user_online')->where(['my_user_id'=>$myUserId,'channel_id'=>$channelId])->delete();
            return true;
        }catch(\Exception $e){
            Log::record($e->getMessage().'|offline|','error','error');
            return false;
        }
    }
    /**
     * 插入game_user表数据
     * @param $data
     * @return bool
     */
    public function gameUser($data){

        if(empty($data['my_user_id'])||empty($data['channel_id'])||empty($data['bond_time'])||empty($data['game_id'])){
            Log::record('gameUser insert error:'.json_encode($data));
            return false;
        }

        $db=Db::connect();
        $tables=$db->getTables(config('database.database'));
        $prefix=config('database.prefix');
        krsort($tables);
        $find=false;
        foreach($tables as $v){
            if(match($v,"/^{$prefix}game_user_y_20[0-9][0-9]$/")){
                $game_user=$db->table($v)
                    ->where(['my_user_id'=>$data['my_user_id']])
                    ->where(['game_id'=>$data['game_id']])
                    ->where(['channel_id'=>$data['channel_id']])
                    ->find();

                if($game_user){
                    $find=true;
                    break;
                }
            }
        }
        if($find){
            return true;
        }
        $insertData=[
            'my_user_id'=>$data['my_user_id'],
            'channel_id'=>$data['channel_id'],
            'cps_id'=>$data['cps_id'],
            'game_id'=>$data['game_id'],
            'ip'=>request()->ip(),
            'bond_time'=>$data['bond_time'],
            'device_type'=>$data['device_type'],
            'client_id'=>$this->input->getClientId(),
        ];
        $year=date('Y',$data['bond_time']);
        $tables=get_tables(config('database.database'));
        $prefix=config('database.prefix');
        krsort($tables);
        $tableExists=false;
        foreach($tables as $v){
            if($v==$prefix.'game_user_y_'.$year){
                $tableExists=true;
                break;
            }
        }
        if(!$tableExists){
            $sql = "CREATE TABLE `{$prefix}game_user_y_{$year}` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `my_user_id` varchar(32) NOT NULL COMMENT '用户id',
  `channel_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '渠道id',
  `cps_id` int(10) unsigned DEFAULT '0',
  `game_id` int(10) unsigned DEFAULT '0' COMMENT '游戏id',
  `total_charge` decimal(10,2) unsigned DEFAULT '0.00' COMMENT '累积该游戏充值',
  `ip` varchar(15) DEFAULT '' COMMENT '进入ip',
  `bond_time` int(10) unsigned DEFAULT '0' COMMENT '首次进入时间',
  `device_type` varchar(32) DEFAULT NULL,
  `client_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `1` (`my_user_id`,`game_id`,`channel_id`) USING BTREE,
  KEY `data_inx` (`channel_id`,`bond_time`),
  KEY `channel_id` (`channel_id`) USING BTREE
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='用户首次进入游戏绑定数据';";

            try{
                Db::execute($sql);//创建表
            }catch(\Exception $e){
                Log::record('create game_user_y_'.$year.' table error.'.$e->getMessage());
            }
        }
        try{
            Db::name('game_user_y_'.$year)->insert($insertData);

            return true;
        }catch(\Exception $e){
            Log::record('gameUser insert error:'.$e->getMessage().'|data:'.json_encode($insertData));
            return false;
        }
    }
    /**
     * 记录game_user_log日志
     * @param $data
     * @return bool
     */
    public function gameUserLog($data){
        if(isset($data['in_time'])&&$data['in_time']>0){
            $time=$data['in_time'];
        }else{
            $time=time();
        }
        $month=date('Ym',$time);
        $tables=get_tables(config('database.database'));
        $prefix=config('database.prefix');
        krsort($tables);
        $tableExists=false;
        foreach($tables as $v){
            if($v==$prefix.'game_user_log_m_'.$month){
                $tableExists=true;
                break;
            }
        }
        if(!$tableExists){
            $sql = "CREATE TABLE `{$prefix}game_user_log_m_{$month}` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `my_user_id` char(16) NOT NULL DEFAULT '' COMMENT '用户id',
  `channel_id` int(10) DEFAULT '0' COMMENT '渠道代号',
  `cps_id` int(10) DEFAULT NULL,
  `game_id` int(10) DEFAULT '0' COMMENT '游戏id',
  `server_id` varchar(64) DEFAULT NULL,
  `server_name` varchar(64) DEFAULT NULL,
  `role_id` varchar(64) DEFAULT NULL,
  `role_name` varchar(64) DEFAULT NULL,
  `party_name` varchar(64) DEFAULT NULL,
  `level` int(11) DEFAULT NULL,
  `vip` int(11) DEFAULT NULL,
  `in_time` int(10) unsigned DEFAULT '0' COMMENT '绑定时间',
  `start_time` int(11) DEFAULT NULL,
  `device_type` varchar(10) DEFAULT NULL,
  `ip` varchar(30) DEFAULT NULL,
  `ver` varchar(10) DEFAULT NULL,
  `client_id` int(10) DEFAULT '0' COMMENT 'clientId',
  PRIMARY KEY (`id`),
  KEY `gmi` (`game_id`,`my_user_id`,`in_time`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='进入游戏日志';";

            try{
                Db::execute($sql);//创建表
            }catch(\Exception $e){
                Log::record('create game_user_log_m_'.$month.' table error.'.$e->getMessage(),'error','error');
            }
        }
        try{
            $data['client_id']=$this->input->getClientId();
            Db::name('game_user_log_m_'.$month)->insert($data);
            return true;
        }catch(\Exception $e){
            Log::record($e->getMessage().'|gameUserLog|'.json_encode($data),'error','error');
            return false;
        }
    }
    /**
     * 插入game_user_role数据
     * @param $data
     * @return bool
     */
    public function gameUserRole($data){
        if(empty($data['my_user_id'])||empty($data['channel_id'])||empty($data['create_time'])
            ||empty($data['server_id'])||empty($data['role_id'])){
            Log::record('gameUserRole insert error:'.json_encode($data));
            return false;
        }

        $insertData=[
            'my_user_id'=>$data['my_user_id'],
            'channel_id'=>$data['channel_id'],
            'cps_id'=>$data['cps_id'],
            'game_id'=>$data['game_id'],
            'ip'=>$data['ip'],
            'server_id'=>$data['server_id'],
            'server_name'=>$data['server_name'],
            'role_id'=>$data['role_id'],
            'role_name'=>$data['role_name'],
            'level'=>$data['level'],
            'vip'=>$data['vip'],
            'party_name'=>$data['party_name'],
            'level_change_time'=>$data['level_change_time'],
            'create_time'=>$data['create_time'],
            'device_type'=>$data['device_type'],
            'client_id'=>$this->input->getClientId(),
        ];
        $year=date('Y',$data['create_time']);
        $tables=get_tables(config('database.database'));
        $prefix=config('database.prefix');
        krsort($tables);
        $tableExists=false;
        foreach($tables as $v){
            if($v==$prefix.'game_user_role_y_'.$year){
                $tableExists=true;
                break;
            }
        }
        if(!$tableExists){
            $sql = "CREATE TABLE `{$prefix}game_user_role_y_{$year}` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `my_user_id` varchar(32) NOT NULL,
  `my_user_name` varchar(64) DEFAULT NULL,
  `channel_id` int(10) DEFAULT NULL,
  `cps_id` int(10) unsigned DEFAULT '0',
  `game_id` int(10) unsigned DEFAULT '0',
  `ip` varchar(20) DEFAULT NULL,
  `server_id` varchar(64) DEFAULT '',
  `server_name` varchar(64) DEFAULT '0',
  `role_id` varchar(64) DEFAULT '0',
  `role_name` varchar(64) DEFAULT NULL,
  `level` varchar(30) DEFAULT NULL,
  `vip` varchar(30) DEFAULT NULL,
  `party_name` varchar(30) DEFAULT NULL,
  `level_change_time` int(11) DEFAULT NULL,
  `create_time` int(10) DEFAULT NULL,
  `device_type` varchar(20) DEFAULT NULL,
  `ver` varchar(10) DEFAULT '',
  `client_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `1` (`my_user_id`,`game_id`,`server_id`,`role_id`) USING BTREE,
  KEY `data_inx` (`channel_id`,`create_time`),
  KEY `create_time` (`create_time`) USING BTREE,
  KEY `channel_id` (`channel_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='渠道用户游戏角色列表';";

            try{
                Db::execute($sql);//创建表
            }catch(\Exception $e){
                Log::record('create game_user_role_y_'.$year.' table error.'.$e->getMessage(),'error','error');
            }
        }
        try{
            Db::name('game_user_role_y_'.$year)->insert($insertData);
            return true;
        }catch(\Exception $e){
            Log::record('gameUserRole insert error:'.$e->getMessage().'|data:'.json_encode($insertData),'error','error');
            return false;
        }
    }
    /**
     * 记录game_user_role_log日志
     * @param $data
     * @return bool
     */
    public function gameUserRoleLog($data){
        if(isset($data['create_time'])&&$data['create_time']>0){
            $time=$data['create_time'];
        }else{
            $time=time();
        }
        $year=date('Y',$time);
        $tables=get_tables(config('database.database'));
        $prefix=config('database.prefix');
        krsort($tables);
        $tableExists=false;
        foreach($tables as $v){
            if($v==$prefix.'game_user_role_y_'.$year){
                $tableExists=true;
                break;
            }
        }
        if(!$tableExists){
            $sql = "CREATE TABLE `{$prefix}game_user_role_y_{$year}` (
  `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `my_user_id` varchar(32) NOT NULL,
  `my_user_name` varchar(64) DEFAULT NULL,
  `channel_id` int(10) DEFAULT NULL,
  `cps_id` int(10) unsigned DEFAULT '0',
  `game_id` int(10) unsigned DEFAULT '0',
  `ip` varchar(20) DEFAULT NULL,
  `server_id` varchar(64) DEFAULT '',
  `server_name` varchar(64) DEFAULT '0',
  `role_id` varchar(64) DEFAULT '0',
  `role_name` varchar(64) DEFAULT NULL,
  `level` varchar(30) DEFAULT NULL,
  `vip` varchar(30) DEFAULT NULL,
  `party_name` varchar(30) DEFAULT NULL,
  `level_change_time` int(11) DEFAULT NULL,
  `create_time` int(10) DEFAULT NULL,
  `device_type` varchar(20) DEFAULT NULL,
  `ver` varchar(10) DEFAULT '',
  `client_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `1` (`my_user_id`,`game_id`,`server_id`,`role_id`) USING BTREE,
  KEY `data_inx` (`channel_id`,`create_time`),
  KEY `create_time` (`create_time`) USING BTREE,
  KEY `channel_id` (`channel_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8 COMMENT='渠道用户游戏角色列表';";

            try{
                Db::execute($sql);//创建表
            }catch(\Exception $e){
                Log::record('create game_user_role_y_'.$year.' table error.'.$e->getMessage(),'error','error');
            }
        }
        try{
            $data['client_id']=$this->input->getClientId();
            Db::name('game_user_role_y_'.$year)->insert($data);
            return true;
        }catch(\Exception $e){
            Log::record("User->gameUserRoleLog:|".json_encode($data)."|".$e->getMessage(),'error','error');
            return false;
        }
    }

    public function getField($myUserId,$channelId,$field){
        if(empty($myUserId)||empty($channelId)||empty($field)){
            return false;
        }
        $ret='';
        $redis=new Redis();
        if($redis->exists('user:'.$channelId.':id:'.$myUserId)){
            $ret=$redis->hGet('user:'.$channelId.':id:'.$myUserId,$field);
        }else{
            $user=$this->findUserById($myUserId,$channelId);
            if($user&&isset($user[$field])){
                $ret=$user[$field];
            }
        }
        if($field=='user_game_map'){
            return json_decode($ret,true);
        }else{
            return $ret;
        }

    }
    public function getRegCps($myUserId,$gameId,$channelId){
        $ugm=$this->getUserGameMap($myUserId,$channelId);
        if($ugm){
            if(isset($ugm[$gameId]['channel']['cps_id'])){
                return $ugm[$gameId]['channel']['cps_id'];
            }else{
                return false;
            }
        }else{
            return false;
        }
    }

    /**
     * 获取用户任意字段,user_game_map除外,sdkdrive checklogin专用
     * @param $myUserId
     * @param $field
     * @return bool|mixed|string
     */
    public function getChUserField($myUserId,$field){
        if(empty($myUserId)||empty($field)){
            return false;
        }
        $ret='';
        $user=Db::name('user')
            ->where(['my_user_id'=>$myUserId,'channel_id'=>['neq',1000]])
            ->find();
        if($user&&isset($user[$field])){
            $ret=$user[$field];
        }
        return $ret;

    }



    public function getChUserId($myUserId,$channelId){
        $user=$this->findUserById($myUserId,$channelId);
        if($user){
            return $user['ch_user_id'];
        }else{
            return false;
        }
    }
    //------------------------------------------以下是私有方法---------------------------------------------------------
    /**
     * 将用户信息存入缓存
     * @param $userInfo
     */
    private function _cache_user($userInfo){

        if(empty($userInfo['my_user_id'])){
            Out::exception('error:U0002');
        }
        if(empty($userInfo['ch_user_id'])){
            Out::exception('error:U0003');
        }
        if(empty($userInfo['channel_id'])){
            Out::exception('error:U0004');
        }
        if($userInfo['channel_id']==1000){
            if(empty($userInfo['my_user_name'])){
                Out::exception('error:U0015');
            }
        }


        $redis=new Redis();
        $ttl=(int)config('user_ttl');
        $keyId='user:'.$userInfo['channel_id'].':id:'.$userInfo['my_user_id'];
        $keyName='user:'.$userInfo['channel_id'].':name:'.$userInfo['my_user_name'];
        $keyCh='user:'.$userInfo['channel_id'].':ch:'.$userInfo['ch_user_id'];
        if(!$redis->exists($userInfo['my_user_id'])){
            $this->users[$userInfo['channel_id']][$userInfo['my_user_id']]=$userInfo;
            if(isset($userInfo['user_game_map'])&&is_array($userInfo['user_game_map'])){
                $userInfo['user_game_map']=json_encode($userInfo['user_game_map']);
            }
            $redis->hMset($keyId,$userInfo);
            $redis->expire($keyId,$ttl);
            if($userInfo['channel_id']==1000){
                $redis->hMset($keyName,['my_user_id'=>$userInfo['my_user_id'],'password'=>$userInfo['password']]);
                $redis->expire($keyName,$ttl);
            }
            $redis->hMset($keyCh,['my_user_id'=>$userInfo['my_user_id']]);
            $redis->expire($keyCh,$ttl);

        }




    }


    /**
     * 更新缓存
     * @param $myUserId
     * @param $channelId
     * @param $hashKey
     * @param $value
     * @return bool
     */
    protected function _update_cache_by_id($myUserId,$channelId,$hashKey,$value=''){
        if(empty($myUserId)){
            Out::exception('error:U0005');
        }
        if(empty($channelId)){
            Out::exception('error:U0006');
        }
        if(empty($hashKey)){
            Out::exception('error:U0007');
        }

        $keyId='user:'.$channelId.':id:'.$myUserId;
        $redis=new Redis();
        if(is_array($hashKey)){
            $data=$hashKey;
            $redis->hMset($keyId,$data);
            //更新users数组
            $this->_update_users_array($myUserId,$channelId,$data);
        }else{
            $redis->hMset($keyId,[$hashKey=>$value]);
            $this->_update_users_array($myUserId,$channelId,[$hashKey=>$value]);//更新users数组
        }

        return true;
    }

    /**
     * 更新缓存
     * @param $myUserName
     * @param $channelId
     * @param $hashKey
     * @param $value
     * @return bool
     */
    protected function _update_cache_by_name($myUserName,$channelId,$hashKey,$value=''){
        if(empty($myUserName)){
            Out::exception('error:U0008');
        }
        if(empty($channelId)){
            Out::exception('error:U0009');
        }
        if(empty($hashKey)){
            Out::exception('error:U0010');
        }

        $keyName='user:'.$channelId.':name:'.$myUserName;
        $redis=new Redis();
        $myUserId=$redis->hGet($keyName,'my_user_id');
        $keyId='user:'.$channelId.':id:'.$myUserId;
        if(is_array($hashKey)){
            $data=$hashKey;
            $redis->hMset($keyId,$data);
            //更新users数组
            $this->_update_users_array($myUserId,$channelId,$data);
        }else{
            $redis->hMset($keyId,[$hashKey=>$value]);
            $this->_update_users_array($myUserId,$channelId,[$hashKey=>$value]);//更新users数组
        }

        return true;
    }

    /**
     * 从缓存获取用户数据,不包含user_game_map
     * @param $myUserId
     * @param $channelId
     * @param string $field
     * @return bool
     */
    private function _get_cache_by_id($myUserId,$channelId,$field=''){
        if(empty($myUserId)){
            Out::exception('error:U0011');
        }
        if(empty($channelId)){
            Out::exception('error:U0012');
        }

        $key='user:'.$channelId.':id:'.$myUserId;
        $redis=new Redis();
        $data=$redis->hGetAll($key);
        if($field==''){
            if(isset($data['user_game_map'])){
                $data['user_game_map']=json_decode($data['user_game_map'],true);
            }
            return $data;
        }else{
            if(!is_array($field)){
                if($field=='user_game_map'){
                    return json_decode($data['user_game_map'],true);
                }else{
                    return $data[$field];
                }
            }else{
                return false;
            }
        }

    }

    /**
     * 从缓存获取用户数据
     * @param $myUserName
     * @param $channelId
     * @param string $field
     * @return bool
     */
    private function _get_cache_by_name($myUserName,$channelId,$field=''){
        if(empty($myUserName)){
            Out::exception('error:U0013');
        }
        if(empty($channelId)){
            Out::exception('error:U0014');
        }


        $keyName='user:'.$channelId.':name:'.$myUserName;

        $redis=new Redis();
        $data=$redis->hGetAll($keyName);
        if(empty($data)||empty($data['my_user_id'])){
            return false;
        }
        $myUserId=$data['my_user_id'];
        if(empty($myUserId)){
            return false;
        }
        $keyId='user:'.$channelId.':id:'.$myUserId;
        if($field==''){
            $data=$redis->hGetAll($keyId);
        }else{
            $data=$redis->hGet($keyId,$field);
        }
        if(isset($data['user_game_map'])){
            $ugm=json_decode($data['user_game_map'],true);
            $data['user_game_map']=$ugm;
        }
        return $data;
    }


    /**
     * 获取用户数据
     * @param $myUserId
     * @param $channelId
     * @param array $fields
     * @return array|bool|false|\PDOStatement|string|\think\Model
     */
    private function _get_db_by_id($myUserId,$channelId,array $fields=[]){
        if(empty($myUserId)||empty($channelId)){
            Log::record("User->_get_db_by_id:{$myUserId}|{$channelId}|".json_encode($fields),'error','error');
            return false;
        }
        if(empty($fields)){
            $fields='*';
        }
        try{
            $user=Db::name('user')
                ->field($fields)
                ->where(['my_user_id'=>$myUserId,'channel_id'=>$channelId])
                ->find();

            if($user){
                $ugm=json_decode($user['user_game_map'],true);
                $user['user_game_map']=$ugm;
                return $user;
            }else{
                return false;
            }

        }catch(\Exception $e){
            Log::record("User->_get_db_by_id:{$myUserId}|{$channelId}|".json_encode($fields).$e->getMessage(),'exception','error');
            return false;
        }
    }

    /**
     * 获取用户数据
     * @param $myUserName
     * @param $channelId
     * @param array $fields
     * @return array|bool|false|\PDOStatement|string|\think\Model
     */
    private function _get_db_by_name($myUserName,$channelId,array $fields=[]){
        if(empty($myUserName)||empty($channelId)){
            Log::record("User->_get_db_by_name:{$myUserName}|{$channelId}|".json_encode($fields),'error','error');
            return false;
        }
        if(empty($fields)){
            $fields='*';
        }
        try{
            $user=Db::name('user')
                ->field($fields)
                ->where(['my_user_name'=>$myUserName,'channel_id'=>$channelId])
                ->find();
            if($user){
                $ugm=json_decode($user['user_game_map'],true);
                $user['user_game_map']=$ugm;
                return $user;
            }else{
                return false;
            }

        }catch(\Exception $e){
            Log::record("User->_get_db_by_name:{$myUserName}|{$channelId}|".json_encode($fields).$e->getMessage(),'exception','error');
            return false;
        }
    }

    /**
     * 更新数据库中的一个或多个字段
     * @param $myUserId
     * @param $channelId
     * @param array $data
     * @return bool
     */
    protected function _update_db_by_id($myUserId,$channelId,array $data=[]){
        if(empty($myUserId)||empty($channelId)){
            Log::record("User->_update_db_by_id:{$myUserId}|{$channelId}|".json_encode($data),'error','error');
            return false;
        }
        unset($data['my_user_id']);
        unset($data['channel_id']);
        if(isset($data['user_game_map'])){
            if(is_array($data['user_game_map'])){
                $data['user_game_map']=json_encode($data['user_game_map']);
            }

        }
        try{
            if(isset($data['mili'])){
                $this->_dec_inc($myUserId, $channelId, 'mili', $data['mili']);
                unset($data['mili']);
            }
            if(isset($data['account_times'])){
                $this->_dec_inc($myUserId, $channelId, 'account_times', $data['account_times']);
                unset($data['account_times']);
            }
            if(isset($data['phone_times'])){
                $this->_dec_inc($myUserId, $channelId, 'phone_times', $data['phone_times']);
                unset($data['phone_times']);
            }
            if(isset($data['password_times'])){
                $this->_dec_inc($myUserId, $channelId, 'password_times', $data['password_times']);
                unset($data['password_times']);
            }

            if(empty($data)){
                return true;
            }

            Db::name('user')
                ->where(['my_user_id'=>$myUserId,'channel_id'=>$channelId])
                ->update($data);

            return true;
        }catch(\Exception $e){
            Log::record("User->_update_db_by_id:{$myUserId}|{$channelId}|".json_encode($data).$e->getMessage(),'exception','error');
            return false;
        }

    }

    protected function _dec_inc($myUserId, $channelId, $k, $v){
        $first = substr($v, 0, 1);
        $number = substr($v, 1);
        if($first=='-'){
            Db::name('user')->where(['my_user_id'=>$myUserId,'channel_id'=>$channelId])->setDec($k, $number);
        }else{
            Db::name('user')->where(['my_user_id' => $myUserId, 'channel_id' => $channelId])->setInc($k, $number);
        }
    }

    /**
     * 更新数据库中的一个或多个字段
     * @param $myUserName
     * @param $channelId
     * @param array $data
     * @return bool
     */
    protected function _update_db_by_name($myUserName,$channelId,array $data=[]){
        if(empty($myUserName)||empty($channelId)){
            Log::record("User->_update_db_by_name:{$myUserName}|{$channelId}|".json_encode($data),'error','error');
            return false;
        }
        unset($data['my_user_id']);
        unset($data['channel_id']);
        unset($data['my_user_name']);
        if(isset($data['user_game_map'])){
            $data['user_game_map'] = json_encode($data['user_game_map']);
        }
        try{
            Db::name('user')
                ->where(['my_user_name'=>$myUserName,'channel_id'=>$channelId])
                ->update($data);
            return true;
        }catch(\Exception $e){
            Log::record("User->_update_db_by_name:{$myUserName}|{$channelId}|".json_encode($data).$e->getMessage(),'exception','error');
            return false;
        }

    }

    /**
     * 更新User对象中的用户数组.
     * 当User类初始化时会把查询到的用户存入users中,再次查询时可以直接返回该用户
     * @param $myUserId
     * @param $channelId
     * @param $data
     * @return bool
     */
    private function _update_users_array($myUserId,$channelId,$data){
        if(isset($this->users[$channelId][$myUserId])){
            $user=$this->users[$channelId][$myUserId];
        }else{
            return false;
        }
        if($user){
            foreach($data as $k=>$v){
                if($k=='user_game_map'){
                    if(!is_array($v)){
                        $v=json_decode($v,true);
                    }
                }
                $this->users[$channelId][$myUserId][$k]=$v;
            }
            return true;
        }else{
            return false;
        }

    }




}



